package cn.huiyunche.base.service.interfaces;

import cn.huiyunche.base.service.framework.redis.MindsJedisConnectionFactory;
import cn.huiyunche.base.service.utils.SerializeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;

import javax.annotation.Resource;
import java.util.Set;

@SuppressWarnings({"cast"})
@Service
public class RedisCacheManager {
    private static final Logger logger = LoggerFactory
            .getLogger(RedisCacheManager.class);

    @Resource
    private volatile CacheManager cacheManager;

    @Resource
    private MindsJedisConnectionFactory jedisConnectionFactory;

    /**
     * constructor
     */
    public RedisCacheManager() {
    }

    /**
     * get RedisCacheManager
     *
     * @return
     */
    public CacheManager getCacheManager() {
        if (this.cacheManager == null) {
            RedisCacheManager.logger.error("未注入RedisCacheManager,请检查spring配置.");
        }
        return this.cacheManager;
    }

    /**
     * 指定缓存的过期时间
     *
     * @param cacheName
     * @param key
     * @param value
     * @param seconds
     */
    public void setExpires(String cacheName, String key, String value,
                           int seconds) {
        // //long time = new Date().getTime();
        Jedis jedis = this.getJedis();
        try {
            String expiresKey = cacheName.concat("~").concat(key);
            jedis.setex(expiresKey, seconds, value);
            // //jedis.set(expiresKey, value);
            // //jedis.expireAt(expiresKey, time + expires);
        } catch (Exception e) {
            RedisCacheManager.logger
                    .error("OtsCacheManager setExpires method error:\n"
                            + e.getMessage());
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * @param cacheName
     * @param key
     * @param value
     * @param seconds
     */
    public void setExpires(String cacheName, String key, Object value,
                           int seconds) {
        Jedis jedis = this.getJedis();
        try {
            String expiresKey = cacheName.concat("~").concat(key);
            jedis.setex(expiresKey.getBytes(), seconds,
                    SerializeUtil.serialize(value));
        } catch (Exception e) {
            RedisCacheManager.logger
                    .error("OtsCacheManager setExpires method error:\n"
                            + e.getMessage());
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    /**
     * @param cacheName
     * @param key
     * @return
     */
    public Object getExpiresObject(String cacheName, String key) {
        Object result = null;
        Jedis jedis = this.getJedis();
        try {
            String expiresKey = cacheName.concat("~").concat(key);
            byte[] objBytes = jedis.get(expiresKey.getBytes());
            result = SerializeUtil.unserialize(objBytes);
        } catch (Exception e) {
            result = null;
        } finally {
            if (jedis != null) {
                jedis.close();
            }

        }

        return result;
    }

    /**
     * @param cacheName
     * @param key
     * @return
     */
    public Object getExpires(String cacheName, String key) {
        String result = "";
        Jedis jedis = this.getJedis();
        try {
            String expiresKey = cacheName.concat("~").concat(key);
            result = jedis.get(expiresKey);
        } catch (Exception e) {
            result = "";
        } finally {
            if (jedis != null) {
                jedis.close();
            }

        }
        return result;
    }


    /**
     * 删除指定名称缓存下指定key的值
     *
     * @param cacheName 参数：缓存名称
     * @param key       参数：key
     */
    public void remove(String cacheName, String key) {
        Jedis jedis = this.getJedis();
        try {
            key = cacheName.concat("~").concat(key);
            Set<String> set = jedis.keys(key);
            String[] kk = new String[set.size()];
            jedis.del(set.toArray(kk));

        } catch (Exception e) {
            RedisCacheManager.logger
                    .error("OtsCacheManager remove method error:\n"
                            + e.getMessage());
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    public void del(String key) {
        Jedis jedis = this.getJedis();
        try {
            Set<String> set = jedis.keys(key);
            String[] kk = new String[set.size()];
            jedis.del(set.toArray(kk));
        } catch (Exception e) {
            RedisCacheManager.logger.error("OtsCacheManager del method error:\n"
                    + e.getMessage());
        } finally {
            jedis.close();
        }
    }

    // lpush
    public void lpush(String queneName, String str) {
        Jedis jedis = getJedis();
        try {
            jedis.lpush(queneName, str);
        } catch (Exception e) {
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
    }

    // rpop
    public String rpop(String queneName) {
        Jedis jedis = getJedis();
        String value = null;
        try {
            value = jedis.rpop(queneName);
        } catch (Exception e) {
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return value;
    }

    public boolean isExistKey(String key) {
        Jedis jedis = getJedis();
        try {
            if (jedis.exists(key))
                return true;
        } catch (Exception e) {
        } finally {
            if (jedis != null) {
                jedis.close();
            }
        }
        return false;
    }


    private Jedis getJedis() {

        return this.jedisConnectionFactory.fetchJedisConnector();

    }

    /**
     * 加锁.
     *
     * @param key
     * @param expireTime 超时时间单位秒.
     * @return 锁定的value, 返回null值加锁失败, 供释放锁时使用.
     */
    public String tryLock(String key, int expireTime) {
        Jedis jedis = getJedis();
        try {
            String value = Long.toString(System.currentTimeMillis() + (expireTime * 1000));
            String result = jedis.set(key, value, "NX", "EX", expireTime);
            if (result == null) {
                return null;
            }
            return value;
        } finally {
            jedis.close();
        }
    }

    /**
     * 释放锁,finally中调用.
     *
     * @param key
     * @param value tryLock返回值.
     */
    public void releaseLock(String key, String value) {
        // 加锁失败情况判断.
        if (value == null) {
            return;
        }
        Jedis jedis = getJedis();
        try {
            String cacheValue = jedis.get(key);
            // 超时释放或者当前key已经被其他线程锁定.
            if ((cacheValue == null) || !value.equals(cacheValue)) {
                return;
            }
            jedis.del(key);
        } finally {
            jedis.close();
        }
    }


}
